<html>
    <head>
        <title>State 状态</title>
    </head>
    <body>
        <script>
            // State  状态

                  /*
                      一、 概述

                                        单一状态树，定义应用状态的默认初始值，页面显示所需的数据从"该对象"中读取。

                                            ①、Vuex 使用单一状态树， 用一个对象就包含了全部的应用层级状态。它便作为一个 "唯一数据源" 而存在。  

                                               这也意味着，每个应用将仅仅包含一个 store实例。

                                            ②、单一状态树让我们能够直接地定位任一特定的状态片段，在调用的过程中也能轻易地取得整个当前应用状态的快照。

                                            ③、不可直接对 state 进行更改，需要通过 Mutation （突变）方法来更改。

                                            ④、state 储存在内存中，刷新页面后会丢失

                                            ⑤、state 储存在 store 对象中，把 store 对象叫做 "状态的存储库"
                                        
                  */


                  /*
                     二、将 store (状态存储器) 从根组件 "注入" 到每一个组件中

                                ★、为什么要通过根实例注入store （状态存储器）

                                                由于 Vuex 的状态存储是响应式的，从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态：

                                                            eg: 

                                                                // 创建一个 Counter 组件

                                                                const Counter ={

                                                                    computed:{

                                                                        count(){
                                                                            return store.state.count
                                                                        }
                                                                    }
                                                                }

                                                每当 store.state.count 变化的时候，都会重新求取计算属性，并且触发更新相关联的DOM。

                                                然而，这种模式导致组件依赖全局状态单例。  在模块化的构建系统中，在每个需要使用 state 的组件中需要频繁地导入，并且在测试组件时需要模拟状态。


                                ★、如何注入

                                    Vuex 通过 store 选项，提供了一种机制将状态从根组件 "注入" 到每一个子组件中 (需要调用  Vue.use(Vuex)):

                                        1、在 uni-app 项目根目录下，新建 store 目录，在此目录下新建  index.js 文件。  在 index.js 文件配置如下：

                                                        // 页面路径：   store/index.js

                                                        import Vue from 'vue'
                                                        import Vuex from 'vuex'

                                                        Vue.use(Vuex);  // vue 的插件机制，使用 Vuex插件

                                                        // Vuex.Store 构造器选项
                                                        const store = new Vuex.Store({
                                                            state:{ // 存放状态
                                                                "username":"foo",
                                                                "age":18
                                                            }
                                                        })
                                                        
                                                        export default store;  // 导出store实例

                                            
                                        2、在 main.js 中导入文件

                                                        // 页面路径：  main.js
                                                        import Vue from 'vue'
                                                        import App from './App'
                                                        import store from './store'

                                                        Vue.prototype.$store = store;

                                                        // 把 store 对象提供给 "store" 选项，这可以把 store 的实例注入所有的子组件
                                                        const app = new Vue({
                                                            store,
                                                            ...App
                                                        })

                                                        app.$mount(); // 挂载
                  */  

                  /*
                        三、获取 state

                                  ★\方法1：( 直接导入store 实例对象)

                                                    通过计算属性访问，但是需要在页面的根节点导入 store
                                                    
                                                    -- 页面路径:  pages/index/index.vue---
                                                    <template>
                                                            <view>
                                                                    <text>用户名： {{username}}</text>
                                                            </view>
                                                    </template>
                                                    
                                                    <script>
                                                            import store from '@/store/index.js' ;  // 需要引入 store

                                                            export default{
                                                                data(){
                                                                    return {}
                                                                },

                                                                computed:{
                                                                    username(){
                                                                        return store.state.username;
                                                                    }
                                                                }
                                                            }
                                                    <//script>


                                  ★、方法2：(已经将store 实例挂载在 Vue 原型上，并命名为 $store 属性)

                                                    在组件中，通过组件 vue 实例的 $store 访问到 state 里的数据

                                                    -- 页面路径： pages/index/index.vue ---

                                                    <template>
                                                            <view>
                                                                <text>用户名：{{ username }} </text>
                                                            </view>
                                                    </template>

                                                    <script>
                                                            export default{
                                                                data(){
                                                                    return {}
                                                                },
                                                                computed:{
                                                                    username(){
                                                                        return this.$store.state.username;
                                                                    }
                                                                }
                                                            }
                                                    <//script>
                  */

                  /*
                        四、mapState 辅助函数

                                1、什么是 mapState 辅助函数，为什么用它？

                                            当一个组件需要获取多个状态的时候，将这些状态都声明为计算属性会有些重复和冗余。

                                            为了解决这个问题，我们可以使用  "mapState辅助函数" 帮助我们生成计算属性，让你少按几次按键：
                                            
                                                   ！-- 页面路径： pages/index/index.vue ---

                                                   <template>
                                                        <view>
                                                             <view> 用户名： {{ username}}</view>
                                                             <view> 年龄： {{ age }}</view>
                                                        </view>
                                                   </template>

                                                   <script>
                                                        import {mapState} from 'vuex' // 导入 mapState 辅助函数 (也就是说　mapState是一个函数定义(C#中可以看作委托))
                                                        
                                                        export default {
                                                            data(){
                                                                return {}
                                                            },
                                                            computed:mapState({  // 将计算属性映射到 state 的子集上

                                                                    // 从 state 中拿到数据  剪头函数可使代码更简练

                                                                    username: state => state.username, ★、// 剪头函数无 this ,所以不能访问当前组件实例的属性

                                                                    age: state= > state.age ★、// 剪头函数无 this，所以不能访问当前组件实例的属性
                                                            })
                                                        }
                                                   <//script>

                                2、语法糖：   当映射的计算属性的名称与 state 的子节点名称相同时，我们也可以给 mapState 传一个字符串数组。

                                                    ！-- 页面路径： pages/index/index.vue ---
                                                    <template>
                                                        <view>
                                                             <view>用户名：{{ username }}</view>
                                                             <view>年龄： {{ age }}</view>
                                                        </view>
                                                    </tempalte>

                                                    <script>
                                                        import {mapState} from 'vuex' // 引入 mapState

                                                        export default{
                                                            data(){
                                                                return {}
                                                            },

                                                            computed: mapService([ 
                                                                'username', //映射 this.username 为 store.state.username
                                                                'age'
                                                            ]);
                                                        }
                                                    <//script>

                                3、mapSate 辅助函数中的 "自定义映射逻辑"

                                             mapState辅助函数映射过程中，可以为 state 中的某个状态添加映射到计算属性的自定义逻辑，
                                             
                                             这个自定义逻辑通过一个 "常规函数实现" (于是有了this指向当前组件的Vue实例)


                                                 !--  页面路径：  pages/index/index.vue ---

                                                 <template>
                                                        <view>
                                                            <view>用户名： {{ username}}</view>
                                                            <view>年龄： {{ age }}</view>
                                                        </view>
                                                 </template>

                                                 <script>
                                                        import {mapState} from 'vuex' // 引入 mapState

                                                        export default{
                                                            date(){
                                                                return {
                                                                    firstName:'Li'
                                                                }
                                                            },
                                                            computed: {
                                                                ...mapState({
                                                                    username:function(state){    // 想使用它想使用this，就必须写成常规函数，不能使用剪头函数
                                                                        return this.firstName + '' + state.username;
                                                                    },
                                                                    age:
                                                                })
                                                            }
                                                        }
                                                 <//script>

                                4、使用对象展开运算符
                                
                                            mapState 函数返回的是一个对象。使用对象展开运算符将多个对象合并为一个，以使我们可以将最终对象传给 computed 属性。极大地简化写法：

                                            !-- 页面路径 : pages/index/index.vue ---
                                            <template>
                                                <view>
                                                    <view>用户名： {{ username}}</view>
                                                    <view>年龄： {{ age}}</view>
                                                </view>
                                            </template>

                                            <script> 
                                                import { mapState} from 'vuex' // 引入 mapState

                                                export default {
                                                    data(){
                                                        return{}
                                                    },
                                                    computed:{
                                                        // 使用对象展开运算符将此对象混入到外部对象中去
                                                        ...mapState({
                                                            username:state=> state.username,
                                                            age:state=> state.age
                                                        })
                                                    }
                                                }
                                            <//script>

                  */
        </script>
    </body>
</html>